<!DOCTYPE html>
<!--
Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">

<script>
'use strict';

tr.b.unittest.testSuite(function() {
  function newModel(events) {
    return tr.c.TestUtils.newModelWithEvents([events], {
      shiftWorldToZero: false
    });
  }

  test('schedSwitchRE', function() {
    const re = tr.e.importer.linux_perf._SchedParserTestExports.schedSwitchRE;
    let x = re.exec('prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ' +
        '==> next_comm=SurfaceFlinger next_pid=178 next_prio=112');
    assert.isNotNull(x);
    assert.strictEqual(x[1], 'swapper');
    assert.strictEqual(x[2], '0');
    assert.strictEqual(x[3], '120');
    assert.strictEqual(x[4], 'R');
    assert.strictEqual(x[5], 'SurfaceFlinger');
    assert.strictEqual(x[6], '178');
    assert.strictEqual(x[7], '112');

    x = re.exec('prev_comm=.android.chrome prev_pid=1562 prev_prio=120 prev_state=R ==> next_comm=Binder Thread # next_pid=195 next_prio=120'); // @suppress longLineCheck
    assert.isNotNull(x);
    assert.strictEqual(x[1], '.android.chrome');
    assert.strictEqual(x[5], 'Binder Thread #');

    x = re.exec('prev_comm=Binder Thread # prev_pid=1562 prev_prio=120 prev_state=R ==> next_comm=.android.chrome next_pid=195 next_prio=120'); // @suppress longLineCheck
    assert.isNotNull(x);
    assert.strictEqual(x[1], 'Binder Thread #');
    assert.strictEqual(x[5], '.android.chrome');

    // explicit test for prev_state of D|W
    x = re.exec('prev_comm=.android.chrome prev_pid=1562 prev_prio=120 ' +
        'prev_state=D|W ==> next_comm=Binder Thread # next_pid=195 ' +
        'next_prio=120');
    assert.isNotNull(x);
    assert.strictEqual(x[4], 'D|W');
  });

  test('schedWakeupRE', function() {
    const re = tr.e.importer.linux_perf._SchedParserTestExports.schedWakeupRE;
    const x = re.exec(
        'comm=SensorService pid=207 prio=112 success=1 target_cpu=000');
    assert.isNotNull(x);
    assert.strictEqual(x[1], 'SensorService');
    assert.strictEqual(x[2], '207');
    assert.strictEqual(x[3], '112');
    assert.strictEqual(x[4], '000');
    const y = re.exec(
        'comm=SensorService pid=207 prio=112 target_cpu=000');
    assert.isNotNull(y);
    assert.strictEqual(y[1], 'SensorService');
    assert.strictEqual(y[2], '207');
    assert.strictEqual(y[3], '112');
    assert.strictEqual(y[4], '000');
  });

  test('importOneSequenceWithSchedWakeUp', function() {
    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
    const lines = [
      'ndroid.launcher-584   [001] d..3 12622.506890: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
      '       Binder_1-217   [001] d..3 12622.506918: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D ==> next_comm=ndroid.launcher next_pid=584 next_prio=120', // @suppress longLineCheck
      'ndroid.launcher-584   [001] d..4 12622.506936: sched_wakeup: comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001', // @suppress longLineCheck
      'ndroid.launcher-584   [001] d..3 12622.506950: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
      '       Binder_1-217   [001] ...1 12622.507057: tracing_mark_write: B|128|queueBuffer', // @suppress longLineCheck
      '       Binder_1-217   [001] ...1 12622.507175: tracing_mark_write: E',
      '       Binder_1-217   [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=ndroid.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
    ];

    const m = newModel(lines.join('\n'));
    assert.isFalse(m.hasImportWarnings);

    const thread = m.findAllThreadsNamed('Binder_1')[0];
    const timeSlices = thread.timeSlices;
    assert.strictEqual(timeSlices.length, 4);

    const runningSlice = timeSlices[0];
    assert.strictEqual(runningSlice.schedulingState, SCHEDULING_STATE.RUNNING);
    assert.closeTo(12622506.890, runningSlice.start, 1e-5);
    assert.closeTo(.918 - .890, runningSlice.duration, 1e-5);

    const sleepSlice = timeSlices[1];
    assert.strictEqual(
        sleepSlice.schedulingState, SCHEDULING_STATE.UNINTR_SLEEP);
    assert.closeTo(12622506.918, sleepSlice.start, 1e-5);
    assert.closeTo(.936 - .918, sleepSlice.duration, 1e-5);

    const wakeupSlice = timeSlices[2];
    assert.strictEqual(
        wakeupSlice.schedulingState, SCHEDULING_STATE.RUNNABLE);
    assert.closeTo(12622506.936, wakeupSlice.start, 1e-5);
    assert.closeTo(.950 - .936, wakeupSlice.duration, 1e-5);
    assert.strictEqual(wakeupSlice.args['wakeup from tid'], 584);

    const runningSlice2 = timeSlices[3];
    assert.strictEqual(
        runningSlice2.schedulingState, SCHEDULING_STATE.RUNNING);
    assert.closeTo(12622506.950, runningSlice2.start, 1e-5);
    assert.closeTo(7.253 - 6.950, runningSlice2.duration, 1e-5);
  });

  test('importWithUnknownSleepState', function() {
    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
    const lines = [
      'ndroid.launcher-584   [001] d..3 12622.506890: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
      '       Binder_1-217   [001] d..3 12622.506918: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=F|O ==> next_comm=ndroid.launcher next_pid=584 next_prio=120', // @suppress longLineCheck
      'ndroid.launcher-584   [001] d..4 12622.506936: sched_wakeup: comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001', // @suppress longLineCheck
      'ndroid.launcher-584   [001] d..3 12622.506950: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
      '       Binder_1-217   [001] ...1 12622.507057: tracing_mark_write: B|128|queueBuffer', // @suppress longLineCheck
      '       Binder_1-217   [001] ...1 12622.507175: tracing_mark_write: E',
      '       Binder_1-217   [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=F|O ==> next_comm=ndroid.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
    ];

    let m;
    assert.doesNotThrow(function() {
      m = newModel(lines.join('\n'));
    });
    assert.isTrue(m.hasImportWarnings);
    assert.strictEqual(
        m.importWarnings[0].message, 'Unrecognized sleep state: F|O');

    const thread = m.findAllThreadsNamed('Binder_1')[0];
    const timeSlices = thread.timeSlices;

    assert.strictEqual(timeSlices[1].schedulingState, SCHEDULING_STATE.UNKNOWN);
  });

  test('importWithUninterruptibleSleep', function() {
    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
    const lines = [
      'ndroid.launcher-584   [001] d..3 12622.506890: sched_switch: ' +
          'prev_comm=ndroid.launcher prev_pid=584 ' +
          'prev_prio=120 prev_state=R+ ' +
          '==> next_comm=Binder_1 next_pid=217 next_prio=120',

      '       Binder_1-217   [001] d..3 12622.506918: sched_switch: ' +
          'prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D|K ' +
          '==> next_comm=ndroid.launcher next_pid=584 next_prio=120',

      'ndroid.launcher-584   [001] d..4 12622.506936: sched_wakeup: ' +
          'comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001',

      'ndroid.launcher-584   [001] d..3 12622.506950: sched_switch: ' +
          'prev_comm=ndroid.launcher prev_pid=584 ' +
          'prev_prio=120 prev_state=R+ ' +
          '==> next_comm=Binder_1 next_pid=217 next_prio=120',

      '       Binder_1-217   [001] ...1 12622.507057: tracing_mark_write: ' +
          'B|128|queueBuffer',

      '       Binder_1-217   [001] ...1 12622.507175: tracing_mark_write: E',

      '       Binder_1-217   [001] d..3 12622.507253: sched_switch: ' +
          'prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ' +
          '==> next_comm=ndroid.launcher next_pid=584 next_prio=120'
    ];

    const m = newModel(lines.join('\n'));
    assert.isFalse(m.hasImportWarnings);

    const thread = m.findAllThreadsNamed('Binder_1')[0];
    const timeSlices = thread.timeSlices;
    assert.strictEqual(timeSlices.length, 4);

    const wakeKillSlice = timeSlices[1];
    assert.strictEqual(wakeKillSlice.schedulingState,
        SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL);
    assert.closeTo(12622506.918, wakeKillSlice.start, 1e-5);
    assert.closeTo(.936 - .918, wakeKillSlice.duration, 1e-5);
  });

  test('importWithUninterruptibleSleepAndBlockedReason', function() {
    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
    const lines = [
      'ndroid.launcher-584   [001] d..3 12622.506890: sched_switch: ' +
          'prev_comm=ndroid.launcher prev_pid=584 ' +
          'prev_prio=120 prev_state=R+ ' +
          '==> next_comm=Binder_1 next_pid=217 next_prio=120',

      '       Binder_1-217   [001] d..3 12622.506918: sched_switch: ' +
          'prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D|K ' +
          '==> next_comm=ndroid.launcher next_pid=584 next_prio=120',

      '       Binder_1-217   [001] d..3 12622.506930: sched_blocked_reason: ' +
          'pid=217 iowait=1 caller=sleep_on_page_killable+0x10/0x4c',

      'ndroid.launcher-584   [001] d..4 12622.506936: sched_wakeup: ' +
          'comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001',

      'ndroid.launcher-584   [001] d..3 12622.506950: sched_switch: ' +
          'prev_comm=ndroid.launcher prev_pid=584 ' +
          'prev_prio=120 prev_state=R+ ' +
          '==> next_comm=Binder_1 next_pid=217 next_prio=120',

      '       Binder_1-217   [001] ...1 12622.507057: tracing_mark_write: ' +
          'B|128|queueBuffer',

      '       Binder_1-217   [001] ...1 12622.507175: tracing_mark_write: E',

      '       Binder_1-217   [001] d..3 12622.507253: sched_switch: ' +
          'prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ' +
          '==> next_comm=ndroid.launcher next_pid=584 next_prio=120'
    ];

    const m = newModel(lines.join('\n'));
    assert.isFalse(m.hasImportWarnings);

    const thread = m.findAllThreadsNamed('Binder_1')[0];
    const timeSlices = thread.timeSlices;
    assert.strictEqual(timeSlices.length, 4);

    const wakeKillSlice = timeSlices[1];
    assert.strictEqual(wakeKillSlice.schedulingState,
        SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL_IO);
    assert.closeTo(12622506.918, wakeKillSlice.start, 1e-5);
    assert.closeTo(.936 - .918, wakeKillSlice.duration, 1e-5);
  });

  test('importWithTgids', function() {
    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
    const lines = [
      'kworker/u12:4-9393 ( 9393) [002] d..3 10386.798979: sched_switch: ' +
          'prev_comm=kworker/u12:4 prev_pid=9393 prev_prio=120 ' +
          'prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120',
    ];

    const m = newModel(lines.join('\n'));
    assert.isFalse(m.hasImportWarnings);

    const p = m.processes[9393];
    assert.strictEqual(p.pid, 9393);
  });

  test('importWithMissingNames', function() {
    const lines = [
      '       Binder_1-217   (  438) [001] d..3 12622.506918: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=F|O ==> next_comm=ndroid.launcher next_pid=584 next_prio=120', // @suppress longLineCheck
      '<...>-584   (  954) [001] d..4 12622.506936: sched_wakeup: comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001', // @suppress longLineCheck
      'ndroid.launcher-584   (  954) [001] d..3 12622.506950: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
    ];

    const m = newModel(lines.join('\n'));
    assert.isFalse(m.hasImportWarnings);

    const p = m.processes[954];
    const t = p.getThread(584);
    assert.strictEqual(t.name, 'ndroid.launcher');
  });
});
</script>

